package com.system.common.utils;

import java.util.concurrent.*;
import java.util.concurrent.atomic.*;
import java.nio.file.*;
import java.io.*;

public class FileContentChange {

    private static final int NUM_THREADS = 10;
    private static final int QUEUE_CAPACITY = 100000;
    private static final int NUM_FILES = 100000;

    private static final String[] FILE_NAMES = new String[NUM_FILES];
    private static final AtomicInteger[] FILE_CONTENTS = new AtomicInteger[NUM_FILES];
    private static final Object[] FILE_LOCKS = new Object[NUM_FILES];

    private static final ScheduledExecutorService SCHEDULER = Executors.newSingleThreadScheduledExecutor();

    private static final BlockingQueue<FileChangeRequest> REQUEST_QUEUE = new ArrayBlockingQueue<>(QUEUE_CAPACITY);

    static {
        for (int i = 0; i < NUM_FILES; i++) {
            FILE_NAMES[i] = "file_" + i + ".txt";
            FILE_CONTENTS[i] = new AtomicInteger();
            FILE_LOCKS[i] = new Object();
        }
    }

    public static void main(String[] args) {
        ExecutorService executor = Executors.newFixedThreadPool(NUM_THREADS);
        SCHEDULER.scheduleAtFixedRate(new FileChangeTask(), 0, 1, TimeUnit.MINUTES);
        while (true) {
            try {
                FileChangeRequest request = REQUEST_QUEUE.take();
                executor.submit(new FileChangeTask(request));
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    private static class FileChangeRequest {
        private final int fileIndex;
        private final char oldChar;
        private final char newChar;

        public FileChangeRequest(int fileIndex, char oldChar, char newChar) {
            this.fileIndex = fileIndex;
            this.oldChar = oldChar;
            this.newChar = newChar;
        }
    }

    private static class FileChangeTask implements Runnable {
        private final FileChangeRequest request;

        public FileChangeTask() {
            this(null);
        }

        public FileChangeTask(FileChangeRequest request) {
            this.request = request;
        }

        @Override
        public void run() {
            if (request == null) {
                for (int i = 0; i < NUM_FILES; i++) {
                    synchronized (FILE_LOCKS[i]) {
                        AtomicInteger content = FILE_CONTENTS[i];
                        if (content.get() == 'a') {
                            content.set('b');
                        } else {
                            content.set('a');
                        }
                        Path filePath = Paths.get(FILE_NAMES[i]);
                        try (BufferedWriter writer = Files.newBufferedWriter(filePath)) {
                            writer.write(content.get());
                        } catch (IOException e) {
                            e.printStackTrace();
                        }
                    }
                }
            } else {
                int fileIndex = request.fileIndex;
                synchronized (FILE_LOCKS[fileIndex]) {
                    AtomicInteger content = FILE_CONTENTS[fileIndex];
                    if (content.get() == request.oldChar) {
                        content.set(request.newChar);
                    }
                    Path filePath = Paths.get(FILE_NAMES[fileIndex]);
                    try (BufferedWriter writer = Files.newBufferedWriter(filePath)) {
                        writer.write(content.get());
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }
        }
    }
}
